package org.jenkinsci.plugins.p4scm.utils;

import hudson.EnvVars;
import hudson.Util;
import hudson.model.Computer;
import hudson.model.Node;
import hudson.slaves.NodeProperty;
import hudson.slaves.EnvironmentVariablesNodeProperty;

import java.io.IOException;
import java.util.Map;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import jenkins.model.Jenkins;

import org.jenkinsci.plugins.p4scm.P4SCM;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author yzhou-citrix
 *
 */
public class NodeSubstitutionHelper {
    
    private static final Logger logger = LoggerFactory.getLogger(NodeSubstitutionHelper.class);
    
    private NodeSubstitutionHelper() {
        
    }

    /**
     * Gets default variable substitutions for the {@link Node}.
     * The method injects global and node-specific {@link EnvironmentVariablesNodeProperty}
     * instances.
     * @param instance Instance of {@link P4SCM}
     * @param node Target node. Can be null
     * @param target Output collection
     * @throws InterruptedException 
     */
    public static void getDefaultNodeSubstitutions(
            @Nonnull P4SCM instance, 
            @CheckForNull Node node,
            @Nonnull Map<String, String> target) throws InterruptedException {
     
        // Global node properties
        for (NodeProperty<?> globalNodeProperty: Jenkins.getInstance().getGlobalNodeProperties()) {
            if (globalNodeProperty instanceof EnvironmentVariablesNodeProperty) {
                target.putAll(((EnvironmentVariablesNodeProperty)globalNodeProperty).getEnvVars());
            }
        }
             
        // Local node properties
        if (node != null) {
            for (NodeProperty<?> nodeProperty : node.getNodeProperties()) {
                if (nodeProperty instanceof EnvironmentVariablesNodeProperty) {
                    target.putAll(((EnvironmentVariablesNodeProperty) nodeProperty).getEnvVars());
                }
            }
       
            final String nodeName = node.getNodeName();
            
            // Push legacy variables
            target.put("nodename", nodeName);
            target.put("hostname", getHostName(node));
            target.put("hash", getNodeHash(node));
            
            // Push modern variables
            target.put("NODE_NAME", nodeName.isEmpty() ? "master" : nodeName);
            target.put("NODE_LABELS", Util.join(node.getAssignedLabels(), " "));
            
            // Get environment
            Computer c = node.toComputer();
            if (c != null) {
                try {
                    EnvVars env = c.getEnvironment().overrideAll(target);
                    target.putAll(env);
                } catch (IOException ex) {
                    // Ignore exception
                }
            }
        }
        
    }
    
   /* 
    * Get a unique {@link Node} hashcode.
    * Use hashcode of the nodename to get a unique, slave-specific client name
    * @param node Node
    * @return 
    */
   @Nonnull
   private static String getNodeHash(@Nonnull Node node) {
       return String.valueOf(node.getNodeName().hashCode());
   }
   
   @Nonnull
   private static String getHostName(@Nonnull Node node) throws InterruptedException {
       String host = null;
       try {
           Computer c = node.toComputer();
           if (c != null) {
               host = c.getHostName();
           }
       } catch (IOException ex) {
           // fallback to finally
       } finally {
           if (host == null) {
               logger.error("Could not get hostname for slave {}", node.getDisplayName());
               host = "UNKNOWNHOST";
           }
       }
       if (host.contains(".")) {
           host = String.valueOf(host.subSequence(0, host.indexOf('.')));
       }
       return host;
   }

}
